<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
  <meta charset="utf-8">
  <script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
  <script src="wct-browser-config.js"></script>
  <script src="../../node_modules/wct-browser-legacy/browser.js"></script>
  <script type="module" src="../../polymer-legacy.js"></script>
</head>
<body>

  <x-scope></x-scope>

  <dom-module id="story-card">
    <template>
    <style>
      :host {
        display: block;
      }

      #story-card .story-content {
        font-family: 'Roboto', sans-serif;
        font-size: 1.2em;
        @apply --story-content;
      }
    </style>

      <div id="story-card">
        <div class="story-content" id="content">Content</div>
      </div>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'story-card'});
</script>
  </dom-module>

  <dom-module id="x-child-scope">
    <template>
    <style>
      :host {
        display: block;

        --mixin2: {
          border: 3px solid seagreen;
          background: url(http://www.google.com/icon.png);
        };
      }

      #mixin1 {
        @apply --mixin1;
      }

      #mixin2 {
        @apply --mixin2;
      }

      #mixin3 {
        padding: 3px;
        @apply --mixin3;
      }

      #mixin4 {
        @apply --mixin4;
      }

      #mixin6 {
        @apply --mixin6
      }

      #mixin7 {@apply --mixin7}

      #mixin8 {
        @apply --mixin8
      }

      #mixin9 {
        @apply --mixin9
      }
    </style>

      <div id="mixin1">mixin1</div>
      <div id="mixin2">mixin2</div>
      <div id="mixin3">mixin3</div>
      <div id="mixin4">mixin4</div>
      <div id="mixin6">mixin6</div>
      <div id="mixin7">mixin7</div>
      <div id="mixin8">mixin8</div>
      <div id="mixin9">mixin9</div>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-child-scope'});
</script>
  </dom-module>

  <dom-module id="x-keyframes">
    <template>
      <style>
        :host {
          display: block;
          position: relative;
          border: 10px solid blue;
          left: 0px;
          /* Prefix required by Safari <= 8 */
          -webkit-animation-duration: 0.3s;
          animation-duration: 0.3s;
          -webkit-animation-fill-mode: forwards;
          animation-fill-mode: forwards;
        }

        :host([animated]) {
          /* Prefix required by Safari <= 8 */
          -webkit-animation-name: x-keyframes-animation;
          animation-name: x-keyframes-animation;
        }

        /* Prefix required by Safari <= 8 */
        @-webkit-keyframes x-keyframes-animation {
          0% {
            left: var(--c1);
          }

          100% {
            left: var(--c2);
            @apply --keyframe-finish;
          }
        }
        @keyframes x-keyframes-animation {
          0% {
            left: var(--c1);
          }

          100% {
            left: var(--c2);
            @apply --keyframe-finish;
          }
        }
      </style>
      x-keyframes
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-keyframes',
  properties: {
    animated: {
      type: Boolean,
      value: false,
      reflectToAttribute: true
    }
  }
});
</script>
  </dom-module>

  <dom-module id="x-scope">
    <template>
    <style>
      :host {
        display: block;
        padding: 8px;

        --override-me: {
          border: 11px solid black;
        };

        --mixin1: {
          border: 1px solid black;
        };

        --b: 2px solid orange;

        --m1: 1px;
        --m2: 2px;

        --c1: 5px;
        --c2: 10px;

        --mixin2: {
          border: var(--b);
        };

        --mixin3: {
          @apply --mixin2;
        };

        --mixin4: {
          padding: 2px;
          @apply --mixin3;
          margin: var(--m2);
        };

        --mixin5: {
          border: calc(var(--c1) + var(--c2)) solid orange;
        };

        --mixin6: {
          border: 16px solid orange;
        };

        --mixin7: {
          border: 17px solid navy;
        };

        --mixin8: {
          border: 17px dotted navy;
        };

        --mixin9: var(--mixin8);
      }

      #mixin1 {
        @apply --mixin1;
      }

      #mixin2 {
        @apply --mixin2;
      }

      #mixin3 {
        padding: 1px;
        margin: var(--m1);
        @apply --mixin3;
      }

      #mixin4 {
        @apply --mixin4;
      }

      #mixin5 {
        @apply --mixin5;
      }

      #keyframes2 {
        --keyframe-finish: {
          left: 20px;
        };
      }

      x-child-scope {
        padding: 10px;
      }

      #card {
        --story-content: {
          border: 11px solid orange;
        };
      }

      #override {
        @apply --override-me;
        border: 19px solid steelblue;
      }

    </style>

      <div id="mixin1">mixin1</div>
      <div id="mixin2">mixin2</div>
      <div id="mixin3">mixin3</div>
      <div id="mixin4">mixin4</div>
      <div id="mixin5">mixin5</div>
      <hr>
      <x-keyframes id="keyframes1"></x-keyframes>
      <x-keyframes id="keyframes2"></x-keyframes>
      <x-child-scope id="child"></x-child-scope>
      <story-card id="card"></story-card>
      <div id="override">override</div>
    </template>
    <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-scope'});
</script>
  </dom-module>

  <dom-module id="x-var-produce-via-consume">
  <template>
    <style>
      :host {
        display: block;
        border: 10px solid orange;
        --foo: {
          color: var(--bar);
        }
      }
    </style>
        </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-var-produce-via-consume'
});
</script>
</dom-module>

<dom-module id="x-cache-child">
  <template>
    <style>
    :host {
      display: block;
      color: var(--foo);
      @apply --bar;
    }
    </style>
    X
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-cache-child'
});
</script>
</dom-module>

<dom-module id="x-cache-host-1">
  <template>
    <style>
    :host {
      display: block;
      --foo: blue;
      --bar: {
        border: 10px solid black;
      };
    }
    </style>
    <x-cache-child id="child"></x-bad-child>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-cache-host-1'
});
</script>
</dom-module>

<dom-module id="x-cache-host-2">
  <template>
    <style>
    :host {
      display: block;
      --foo: blue;
      --bar: {
        border: 1px dotted green;
      };
    }
    </style>
    <x-cache-child id="child"></x-bad-child>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-cache-host-2'
});
</script>
</dom-module>

<dom-module id="x-no-paren-apply-only">
  <template>
    <style>
    :host {
      --bar: {
        border: 2px solid green;
      }
    }
    #child {
      @apply --bar;
    }
    </style>
    <div id="child">X</div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
  is: 'x-no-paren-apply-only'
});
</script>
</dom-module>

<dom-module id="x-redefine-three">
  <template>
    <style>
      div {
        @apply --redefine;
      }
    </style>
    <div id="div"></div>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-redefine-three'});
</script>
</dom-module>

<dom-module id="x-redefine-two">
  <template>
    <style>
      x-redefine-three {
        --redefine: {
          border: 2px solid gray;
        };
      }
    </style>
    <x-redefine-three id="three"></x-redefine-three>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-redefine-two'});
</script>
</dom-module>

<dom-module id="x-redefine-one">
  <template>
    <style>
      x-redefine-two {
        --redefine: {
          height: 100px;
          width: 100px;
        };
      }
    </style>
    <x-redefine-two id="two"></x-redefine-two>
  </template>
  <script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-redefine-one'});
</script>
</dom-module>

<dom-module id="order-child">
  <template>
    <style>
      div {
        @apply --order-mixin;
      }
    </style>
    <div id="target"></div>
  </template>
</dom-module>

<dom-module id="order-parent">
  <template>
    <style>
      order-child {
        --order-mixin: {
          border: 10px solid black;
        };
      }
    </style>
    <order-child id="child"></order-child>
  </template>
</dom-module>

<dom-module id="order-gp">
  <template>
    <style>
      order-child {
        --order-mixin: {
        };
      }
    </style>
    <order-child id="child"></order-child>
    <order-parent id="parent"></order-parent>
  </template>
</dom-module>

<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'order-child'});
Polymer({is: 'order-parent'});
Polymer({is: 'order-gp'});
</script>
<script type="module">
import { flush } from '../../lib/utils/flush.js';
suite('scoped-styling-apply', function() {
  function assertComputed(element, value, property) {
    var computed = getComputedStyle(element);
    property = property || 'border-top-width';
    assert.equal(computed[property], value, 'computed style incorrect for ' + property);
  }

  var styled = document.querySelector('x-scope');

  test('variable mixins calculated correctly and inherit', function() {
    if (!window.ShadyCSS || ShadyCSS.nativeCss) {
      this.skip();
    }
    var suffix = window.ShadyCSS.ApplyShim._separator + 'border';
    var e = styled;
    let mixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix);
    let mixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix);
    let mixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix);
    let mixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix);
    e = styled.$.child;
    let cmixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix);
    let cmixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix);
    let cmixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix);
    let cmixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix);
    assert.equal(mixin1, cmixin1);
    assert.equal(mixin2, cmixin2);
    assert.equal(mixin3, cmixin3);
    assert.equal(mixin4, cmixin4);
  });

  test('variable mixins apply', function() {
    assertComputed(styled.$.mixin1, '1px');
    assertComputed(styled.$.mixin2, '2px');
    assertComputed(styled.$.mixin3, '2px');
    assertComputed(styled.$.mixin3, '1px', 'padding-top');
    assertComputed(styled.$.mixin3, '1px', 'margin-top');
    assertComputed(styled.$.mixin4, '2px');
    assertComputed(styled.$.mixin4, '2px', 'padding-top');
    assertComputed(styled.$.mixin4, '2px', 'margin-top');
  });

  test('mixins apply with url values', function() {
    var url = 'http://www.google.com/icon.png';
    var e = styled.$.child;
    var actual, unescaped, propertyName;
    if (window.ShadyCSS && ShadyCSS.nativeCssApply) {
      actual = getComputedStyle(e).getPropertyValue('--mixin2');
      // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include
      unescaped = actual.replace(/\\/g, '');
      assert.include(unescaped, url);
    } else if (!window.ShadyCSS || ShadyCSS.nativeCss) {
      propertyName = '--mixin2' + window.ShadyCSS.ApplyShim._separator + 'background';
      actual = getComputedStyle(e).getPropertyValue(propertyName);
      // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include
      unescaped = actual.replace(/\\/g, '');
      assert.include(unescaped, url);
    } else {
      propertyName = '--mixin2';
      actual = ShadyCSS.ScopingShim.getComputedStyleValue(e, propertyName);
      unescaped = actual.replace(/\\/g, '');
      assert.include(unescaped, url);
    }
  });

  test('variable mixins inherit and override', function() {
    var e = styled.$.child;
    assertComputed(e.$.mixin1, '1px');
    assertComputed(e.$.mixin2, '3px');
    assertComputed(e.$.mixin3, '2px');
    assertComputed(e.$.mixin3, '3px', 'padding-top');
    assertComputed(e.$.mixin4, '2px');
    assertComputed(e.$.mixin4, '2px', 'padding-top');
    assertComputed(e.$.mixin4, '2px', 'margin-top');
  });

  test('calc can be used in mixins', function() {
    assertComputed(styled.$.mixin5, '15px');
  });

  test('mixins work with selectors that contain element name', function() {
    assertComputed(styled.$.card.$.content, '11px');
  });

  test('mixins with trailing new line or } apply', function() {
    assertComputed(styled.$.child.$.mixin6, '16px');
    assertComputed(styled.$.child.$.mixin7, '17px');
  });

  test('mixins with new `@apply --foo` syntax', function() {
    assertComputed(styled.$.child.$.mixin8, '17px');
  });

  test('mixins can be realiased with var()', function() {
    assertComputed(styled.$.child.$.mixin9, '17px');
  });

  test('mixins apply to @keyframe rules', function(done) {
    if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {
      // skip test due to missing variable support in keyframes
      // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/
      this.skip();
    }
    var xKeyframes1 = styled.$.keyframes1;
    var xKeyframes2 = styled.$.keyframes2;
    var completed = 0;

    [xKeyframes1, xKeyframes2].forEach(function(xKeyframes, index) {
      var target = index === 0 ? '10px' : '20px';
      var onAnimationEnd = function() {
        assert.include(xKeyframes.getComputedStyleValue('left'), target, xKeyframes.id);

        xKeyframes.removeEventListener('animationend', onAnimationEnd);
        xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
        xKeyframes.animated = false;
        if (++completed > 1) {
          done();
        }
      };

      xKeyframes.addEventListener('animationend', onAnimationEnd);
      xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);

      xKeyframes.animated = true;
    });
  });

  test('producing a var that consumes another var preserves static styling', function() {
    var d = document.createElement('x-var-produce-via-consume');
    document.body.appendChild(d);
    assertComputed(d, '10px');
  });

  test('producing a var that consumes results in static and not dynamic stylesheet', function() {
    var d = document.createElement('x-var-produce-via-consume');
    document.body.appendChild(d);
    var styleRoot = (!window.ShadyDOM || !ShadyDOM.isShadyRoot(d.shadowRoot)) ? d.shadowRoot : document.head;
    var selector = window.ShadyDOM ? 'style[scope~=x-var-produce-via-consume]' : 'style';
    var staticStyle = styleRoot.querySelector(selector);
    assert.ok(staticStyle);
    assert.match(staticStyle.textContent, /display/, 'static style does not contain style content');
    assert.equal(styleRoot.querySelectorAll(selector).length, 1);
  });

  test('mixin values can be overridden by subsequent concrete properties', function() {
    assertComputed(styled.$.override, '19px');
  });

  test('@apply without parens is included in style cache behavior', function() {
    var e1 = document.createElement('x-cache-host-1');
    var e2 = document.createElement('x-cache-host-2');
    document.body.appendChild(e1);
    document.body.appendChild(e2);
    flush();
    assertComputed(e1.$.child, '10px');
    assertComputed(e2.$.child, '1px');
  });

  test('@apply without parens triggers property shim', function() {
    var e = document.createElement('x-no-paren-apply-only');
    document.body.appendChild(e);
    flush();
    assertComputed(e.$.child, '2px');
  });

  test('mixin redefinition resets old properties', function() {
    var e = document.createElement('x-redefine-one');
    document.body.appendChild(e);
    flush();
    var div = e.$.two.$.three.$.div;
    assertComputed(div, '2px');
    assertComputed(div, '0px', 'height');
  });

  test('mixin redefinition applies to complicated hierarchies', function() {
    var e = document.createElement('order-gp');
    document.body.appendChild(e);
    flush();
    var childDiv = e.$.child.$.target;
    var parentDiv = e.$.parent.$.child.$.target;
    assertComputed(childDiv, '0px');
    assertComputed(parentDiv, '10px');
  });
});
</script>
</body>
</html>
